package com.kaibes.web.security.jwt;

import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.kaibes.web.response.ResponseFactory;
import com.kaibes.web.security.core.Token2authentication;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwsHeader;
import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.SignatureException;

@Component
public class JwtToken2authentication implements Token2authentication {
    
    @Override
    public boolean token2authentication(HttpServletResponse response, String token) {
        try {
            token2authentication(token);
            return true;
        } catch (ExpiredJwtException e) {
            sendError(response, "用户登录凭证过期");
        } catch (Exception e) {
            sendError(response, "用户登录凭证无效");
        }
        return false;
    }
    
    private void sendError(HttpServletResponse response, String message) {
        try {
            response.addHeader(ResponseFactory.MESSAGE, ResponseFactory.urlEncode(message));
            response.sendError(HttpStatus.UNAUTHORIZED.value(), message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    @SuppressWarnings({"rawtypes", "unchecked"})
    private static void token2authentication(String token) throws IOException {
        if (!ObjectUtils.isEmpty(token)) {
            Resource resource = new ClassPathResource("public.cert");
            try {
                String strKey = new String(FileCopyUtils.copyToByteArray(resource.getInputStream())).replace("\r\n", "");
                String pem = strKey.replaceAll("\\-*BEGIN PUBLIC KEY\\-*", "").replaceAll("\\-*END PUBLIC KEY\\-*", "").trim();
//              java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
                X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(pem));
                KeyFactory keyFactory = KeyFactory.getInstance("RSA");
                PublicKey publicKey = keyFactory.generatePublic(pubKeySpec);
                Jwt<JwsHeader, Claims> jwt = Jwts.parserBuilder().setSigningKey(publicKey).build().parse(token);
                Claims body = jwt.getBody();
//                String username = body.get("username", String.class);
                Integer userId = body.get("userId", Integer.class);
//                Principal principal = new Principal() {
//                    
//                    @Override
//                    public String getName() {
//                        return String.valueOf(userId);
//                    }
//                };
                Integer roleId = body.get("roleId", Integer.class);
                List<String> authorities = body.get("authorities", ArrayList.class);
                List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
                authorities.forEach(str->grantedAuthorities.add(new SimpleGrantedAuthority(str)));
                Authentication authentication = new UsernamePasswordAuthenticationToken(userId, null, grantedAuthorities);
                SecurityContextHolder.getContext().setAuthentication(authentication);
                HttpServletRequest request = getRequest();
                request.setAttribute("userId", userId);
//                request.setAttribute("username", username);
                request.setAttribute("roleId", roleId);
            } catch (NoSuchAlgorithmException | SignatureException | InvalidKeySpecException e) {
                System.out.println("================================篡改了token");
            }
        }
    }
    
    private static HttpServletRequest getRequest() {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    }

}
